# -*- coding: utf-8 -*-

from __future__ import division
import math
import random
import Action
import Formation
from utility import *

class Lame:
  def __init__(self):
    self.formationHelper = Formation.Helper()
    self.wait = 100

  def __setValues(self, player, game):
    self.minDistanceBetweenFriendsInLine = 20  # minDistanceBetweenFriends (in the line)
    self.maxDistanceBetweenFriendsInLine = 3 * game.field.width / 4 # MaxDistanceBetweenFriends (in the line)
    self.minDistanceBetweenFriendsBetweenLines = 40  # minDistanceBetweenFriends (between lines)
    self.maxDistanceBetweenFriendsBetweenLines = 3 * game.field.length / 4 # MaxDistanceBetweenFriends (between lines) except goal
    self.minAcceptableDistanceToEnnemy      = 10  # minAcceptableDistanceToEnnemy
    self.minAcceptableDistanceOfPassToEnnemy= 10 # minAcceptableDistanceOfPassToEnnemy
    self.minPassDistance    = 30  # minPassDistance
    self.maxPassDistance    = 3 * game.field.width / 4 # maxPassDistance
    self.isTooCloseToEnnemy = False
    self.ballAttraction     = 14
    self.goalAttraction     = 40000
    self.friendAttraction   = -10000
    self.enemyAttraction    = -2000
    self.ballInterception   = 7
    self.initialLocationAttraction = 11

    self.player = player
    self.game   = game
    self.field  = game.field
    self.leftTeam =  player in game.team1.players
    self.myTeam = game.team1 if self.leftTeam else game.team2
    self.opTeam = game.team2 if self.leftTeam else game.team1
    self.myGoal = game.field.getGoal1Location() if self.leftTeam else game.field.getGoal2Location()
    self.opGoal = game.field.getGoal2Location() if self.leftTeam else game.field.getGoal1Location()
    self.role   = self.myTeam.getRoleByPlayer(player)
    self.isGoal = self.role.symbol == "GO"
    self.hasTheBall = player.hasTheBall
    self.isInMyPenaltyArea = game.field.isInPenaltyArea1(player) if self.leftTeam else game.field.isInPenaltyArea2(player)
    self.isInOpPenaltyArea = game.field.isInPenaltyArea2(player) if self.leftTeam else game.field.isInPenaltyArea1(player)
    self.ballInMyPenaltyArea = game.field.isInPenaltyArea1(game.ball) if self.leftTeam else game.field.isInPenaltyArea2(game.ball)
    self.ballInOpPenaltyArea = game.field.isInPenaltyArea2(game.ball) if self.leftTeam else game.field.isInPenaltyArea1(game.ball)
    self.ballDistance = player.location.distance(game.ball.location)
    self.ball = game.ball
    self.defaultLocation = self.formationHelper.getAttackLocation(self.role, self.field, not self.leftTeam) if self.myTeam.isAttacking else self.formationHelper.getStandardLocation(self.role, self.field, not self.leftTeam)
    self.myLine = self.formationHelper.getLineNumber(self.role)

    ce = []
    for p in self.opTeam.players:
      d = self.player.location.distance(p.location)
      if d <= self.minAcceptableDistanceToEnnemy:
        self.isTooCloseToEnnemy = True
      ce.append((p, d))
    self.closestEnnemies = sorted(ce, key=lambda l: l[1])

    cf = []
    for p in self.myTeam.players:
      if p != player:
        cf.append((p, self.player.location.distance(p.location)))
    self.closestFriends = sorted(cf, key=lambda l: l[1])

    self.closerAndSaferFriend = None
    for f in self.closestFriends:
      if self.closerAndSaferFriend == None:
        d = self.player.location.distance(f[0].location)
        if d > self.minPassDistance:
          for e in self.opTeam.players:
            if p.location.distance(e.location) > self.minAcceptableDistanceToEnnemy:
              if self.closerAndSaferFriend == None \
              or not e.isBetweenPlayers(player, f[0], self.minAcceptableDistanceOfPassToEnnemy):
                self.closerAndSaferFriend = f[0]

  def evaluateAction(self, player, game):
    self.__setValues(player, game)
    if game.isThrowingIn:
      if self.wait == -1:
        self.wait = 100
      if self.wait == 0:
        game.isThrowingIn = False
        game.ballOwner.strategy.throwIn(game.ballOwner, game)
      self.wait -= 1
      return Action.Action()
      
    if not player.hasTheBall and self.ballDistance < self.ballInterception:
      return Action.Intercept()

    if self.hasTheBall:
      a = self.__shoot()
      if a != None: return a
      a = self.__doPass()
      if a != None: return a

    v1 = self.__goToBall()
    v2 = self.__goToItsPlace()
    v3 = self.__goAwayFromOthers()
    v4 = self.__goToGoal()
#    v5 = self.__goToRandom()
    v = v1 + v2 + v3 + v4

    return Action.Move(v.getDirection(), v.getNorm())

  def throwIn(self, player, game):
    for p in self.opTeam.players:
      if player.location.distance(p.location) < 50:
        v = self.player.location.getDirectionToTake(p.location).getDirectionVector() * 70
        l = self.player.location + v
        p.location.locate(l)

    self.player.orientation = self.player.location.getDirectionToTake(self.closerAndSaferFriend.location)
    return Action.Shoot()

  def __shoot(self):
    shoot = False
#    for e in self.opTeam.players:
#      shoot &= not e.location.isBetweenLocations(self.player.location, self.opGoal)

    if shoot or self.isInOpPenaltyArea:
      self.player.orientation = self.player.location.getDirectionToTake(self.opGoal)
      return Action.Shoot()
    
    return None

  def __doPass(self):
    if self.isGoal or self.isTooCloseToEnnemy:
      self.player.orientation = self.player.location.getDirectionToTake(self.closerAndSaferFriend.location)
      return Action.Shoot()

    return None

  def __goToBall(self):
    if not self.myTeam.isAttacking and not self.opTeam.isAttacking:
      n = self.ballAttraction * math.exp(-.001 * self.ballDistance / self.field.length)
      d = self.player.location.getDirectionToTake(self.ball.location).getDirectionVector().getNormalizedVector()
      return d * n

    if self.opTeam.isAttacking:
      n = self.ballAttraction * math.exp(-.02 * self.ballDistance / self.field.length)
      d = self.player.location.getDirectionToTake(self.ball.location).getDirectionVector().getNormalizedVector()
      if self.isGoal:
        if self.ballDistance < 2 * self.field.penaltyArea1[3] / 3:
          n *= self.ballAttraction
        if self.ballInMyPenaltyArea:
          n *= self.ballAttraction
      return d * n

    return Vector(0, 0)

  def __goToGoal(self):
    if self.isGoal:
      dd = 3 if self.myTeam.isAttacking else 6
      if self.player.location.distance(self.myGoal) >= self.field.length / dd:
        d = (self.field.length - self.player.location.distance(self.myGoal)) / self.field.length
        v = self.player.location.getDirectionToTake(self.myGoal).getDirectionVector().getNormalizedVector() * self.goalAttraction * math.exp(-.01 * d)
        return v

    if self.myTeam.isAttacking:
      d = self.field.length - self.player.location.distance(self.opGoal)
      v = Vector(1, 0) if self.leftTeam else Vector(-1, 0)
      v = self.player.location.getDirectionToTake(self.opGoal).getDirectionVector().getNormalizedVector() * self.goalAttraction * d
      return v

    return Vector(0, 0)

  def __goToItsPlace(self):
    d = self.player.location.distance(self.defaultLocation) / self.field.length
    v = self.player.location.getDirectionToTake(self.defaultLocation).getDirectionVector().getNormalizedVector() * self.initialLocationAttraction * math.exp(-.01 * d)
    if self.isGoal:
      v *= 2
      if self.opTeam.isAttacking:
        v *= 2
    elif self.opTeam.isAttacking:
      v *= 1.1
    
    return v

  def __goAwayFromOthers(self):
    v = Vector(0, 0)
    for f in self.closestFriends:
      vv = self.player.location.getDirectionToTake(f[0].location).getDirectionVector().getNormalizedVector()
      line = self.formationHelper.getLineNumber(self.myTeam.getRoleByPlayer(f[0]))
      noCase = False
      if line == self.myLine:
        if   f[1] < self.minDistanceBetweenFriendsInLine:       v += vv *  self.friendAttraction * f[1]/2
        elif f[1] > self.maxDistanceBetweenFriendsInLine:       v += vv * -self.friendAttraction * f[1]/2
        else: noCase = True
      elif line == self.myLine - 1 or line == self.myLine + 1:
        if   f[1] < self.minDistanceBetweenFriendsBetweenLines: v += vv *  self.friendAttraction * f[1]/2
        elif f[1] > self.maxDistanceBetweenFriendsBetweenLines: v += vv * -self.friendAttraction * f[1]/2
        else: noCase = True
#      if noCase:
#        average = self.player.location + self.player.location.getTranslationVector(f[0].location) / 2
#        d = self.player.location.distance(average)
#        v += self.player.location.getDirectionToTake(average).getDirectionVector().getNormalizedVector() / 100


    for f in self.closestEnnemies:
      if f[1] < self.minAcceptableDistanceToEnnemy:
        v += self.player.location.getDirectionToTake(f[0].location).getDirectionVector().getNormalizedVector() * self.enemyAttraction * f[1]/2

    return v

#    d1 = player.location.distanceToLine(game.field.borderLineLL[0], game.field.borderLineLL[1]) + 1
#    d2 = player.location.distanceToLine(game.field.borderLineLR[0], game.field.borderLineLR[1]) + 1
#    d3 = player.location.distanceToLine(game.field.borderLineWL[0], game.field.borderLineWL[1]) + 1
#    d4 = player.location.distanceToLine(game.field.borderLineWR[0], game.field.borderLineWR[1]) + 1
#    v1 = v.getNormalizedVector() * (-1 / math.pow(d1/10, 20))
#    v2 = v.getNormalizedVector() * (-1 / math.pow(d2/10, 20))
#    v3 = v.getNormalizedVector() * (-1 / math.pow(d3/10, 20))
#    v4 = v.getNormalizedVector() * (-1 / math.pow(d4/10, 20))
#    v += v1 + v2 + v3 + v4
    

  def __goToRandom(self):
    r = random.randint(0, 7)
    if r == 0: return DirectionHelper.North.getDirectionVector();
    if r == 1: return DirectionHelper.NorthEast.getDirectionVector();
    if r == 2: return DirectionHelper.East.getDirectionVector();
    if r == 3: return DirectionHelper.SouthEast.getDirectionVector();
    if r == 4: return DirectionHelper.South.getDirectionVector();
    if r == 5: return DirectionHelper.SouthWest.getDirectionVector();
    if r == 6: return DirectionHelper.West.getDirectionVector();
    if r == 7: return DirectionHelper.NorthWest.getDirectionVector();
    raise Exception("Unexpected random number.")
